package com.cn.ftp;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import com.cn.exception.MyException;
import com.cn.xc.utils.StringUtil;

/**
 * FUN: FTP操作工具类
 * 
 * @author sushy
 * @date 2016-3-23
 */
public class FtpUtil {

	private static int dataTimeout = 1800000;// 30分钟
	private FtpClient ftpClient;
	private FtpInfo ftpInfo;

	/**
	 * 构造
	 * 
	 * @param ftpInfo
	 */
	public FtpUtil(FtpInfo ftpInfo) {
		this.ftpInfo = ftpInfo;
	}

	/**
	 * connectServer 连接ftp服务器
	 */
	public void connectServer() {
		if (ftpClient == null) {
			ftpClient = new FtpClient();
		}

		try {
			ftpClient.connect(ftpInfo.getIp(), ftpInfo.getPort());
			ftpClient.setControlEncoding("GBK");// 文件名乱码,默认ISO8859-1，不支持中文
			if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
				throw new MyException("", new IOException(ftpClient.getReplyString()), "ftpKey", ftpInfo.getKey());
			}

			if (!ftpClient.login(ftpInfo.getUser(), ftpInfo.getPassword())) {
				throw new MyException("", new IOException(ftpClient.getReplyString()), "ftpKey", ftpInfo.getKey());
			}

			// path是ftp服务下主目录的子目录
			String path = ftpInfo.getWorkBasePath();
			if (path != null && path.length() > 0) {
				ftpClient.changeWorkingDirectory(path);
			}

			// 用2进制上传、下载
			ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
		} catch (IOException e) {
			throw new MyException("", e, "ftpKey", ftpInfo.getKey());
		}
	}

	/**
	 * closeServer 断开与ftp服务器的链接
	 */
	public void closeServer() {
		try {
			if (ftpClient != null && ftpClient.isConnected()) {
				try {
					ftpClient.logout();
				} catch (Throwable t) {
				}
				ftpClient.disconnect();
			}
		} catch (Exception e) {
		}
	}

	/**
	 * upload 上传文件
	 * 
	 * @param newname
	 *            上传后的新文件名
	 * @param filename
	 *            上传的文件
	 */
	public void upload(String filename, String newname) {
		FileInputStream is = null;
		try {
			/** 检查上传文件是否有效 */
			java.io.File file_in = new java.io.File(filename);
			if (!file_in.exists()) {
				throw new MyException("file", filename);
			}
			if (file_in.length() == 0) {
				throw new MyException("file", filename);
			}

			/** 上传之前的临时文件名 */
			String tempName = newname + ftpInfo.getPostfix();

			/** 用2进制上传、下载 */
			ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

			/** 设置被动模式 */
			ftpClient.enterLocalPassiveMode();

			/** 开始上传文件 */
			is = new FileInputStream(file_in);
			ftpClient.setSoTimeout(dataTimeout);
			if (!ftpClient.storeFile(tempName, is)) {
				throw new MyException("", new IOException(ftpClient.getReplyString()), "ftpKey", ftpInfo.getKey(),
						"ftpFile", filename);
			}
			ftpClient.resetSoTimeout();

			if (!newname.equals(tempName)) {
				/** 上传完毕之后再改为原名 */
				if (!ftpClient.rename(tempName, newname)) {
					throw new MyException("", new IOException(ftpClient.getReplyString()), "ftpKey", ftpInfo.getKey(),
							"ftpFile", tempName, "ftpNewFile", newname);
				}
			}
		} catch (IOException e) {
			throw new MyException("", e, "ftpKey", ftpInfo.getKey());
		} finally {
			IOUtils.closeQuietly(is);
			ftpClient.resetSoTimeout();
		}
	}

	/**
	 * upload 上传文件
	 * 
	 * @param filename
	 *            上传的文件
	 */
	public void upload(String filename) {
		String newname = "";
		if (filename.indexOf("/") > -1) {
			newname = filename.substring(filename.lastIndexOf("/") + 1);
		} else {
			newname = filename;
		}
		upload(filename, newname);
	}

	/**
	 * download 从ftp下载文件到本地
	 * 
	 * @param newfilename
	 *            本地生成的文件名
	 * @param filename
	 *            服务器上的文件名
	 */
	public boolean download(String filename, String newfilename) {
		FileOutputStream os = null;
		try {
			/** 用2进制上传、下载 */
			ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

			/** 设置被动模式 */
			ftpClient.enterLocalPassiveMode();

			/** 下载文件 */
			os = new FileOutputStream(newfilename);
			ftpClient.setSoTimeout(dataTimeout);
			return ftpClient.retrieveFile(filename, os);
		} catch (IOException e) {
			throw new MyException("", e, "ftpKey", ftpInfo.getKey(), "ftpFile", filename);
		} finally {
			IOUtils.closeQuietly(os);
			ftpClient.resetSoTimeout();
		}
	}

	/**
	 * 改文件名
	 * 
	 * @param filename
	 * @param newname
	 * @return
	 */
	public void rename(String filename, String newname) {
		try {
			if (!ftpClient.rename(filename, newname)) {
				throw new MyException("", new IOException(ftpClient.getReplyString()), "ftpKey", ftpInfo.getKey(),
						"ftpFile", filename, "ftpNewFile", newname);
			}
		} catch (IOException e) {
			throw new MyException("", e, "ftpKey", ftpInfo.getKey());
		}
	}

	/**
	 * 取得某个目录下的所有文件列表
	 */
	public List<String> getList(String path) {
		List<String> list = new ArrayList<String>();
		try {
			/** 设置被动模式 */
			ftpClient.enterLocalPassiveMode();
			String[] outs = ftpClient.listNames(path);
			if (outs != null && outs.length > 0) {
				for (String f : outs) {
					list.add(f);
				}
			}
		} catch (IOException e) {
			throw new MyException("", e, "ftpKey", ftpInfo.getKey());
		}
		return list;
	}

	/**
	 * 取得某个目录下的所有文件列表
	 */
	public List<String> getFileList(String path) {
		List<String> list = new ArrayList<String>();
		try {
			/** 设置被动模式 */
			ftpClient.enterLocalPassiveMode();
			FTPFile[] ftpFiles = ftpClient.listFiles(path);
			if (ftpFiles != null) {
				for (FTPFile f : ftpFiles) {
					if (f.isFile()) {
						list.add(f.getName());
					}
				}
			}
		} catch (IOException e) {
			throw new MyException(e, "ftpKey", ftpInfo.getKey());
		}
		return list;
	}

	/**
	 * 删除文件
	 * 
	 * @param filename
	 *            要删除的文件
	 */
	public void deleteFile(String filename) {
		try {
			ftpClient.deleteFile(filename);
		} catch (IOException e) {
			// 删除文件失败
			throw new MyException(e, "ftpKey", ftpInfo.getKey());
		}
	}

	/**
	 * 移动文件
	 * 
	 * @param filename
	 *            要移动的文件
	 * @param newDir
	 *            要移到的新目录
	 */
	public void moveFile(String filename, String newDir) {
		try {
			String newFileName = newDir + "/" + filename;
			ftpClient.rename(filename, newFileName);
		} catch (IOException e) {
			throw new MyException(e, "ftpKey", ftpInfo.getKey());
		}
	}

	/**
	 * 切换目录
	 */
	public boolean changeWorkingDirectory(String workpath) {
		try {
			if (StringUtil.isEmpty(workpath)) {
				// 默认在根目录
				return ftpClient.changeWorkingDirectory("/");
			} else {
				return ftpClient.changeWorkingDirectory(workpath);
			}
		} catch (IOException e) {
			throw new MyException(e, "ftpKey", ftpInfo.getKey());
		}
	}

}
